#include "logger.h"
#include <stdlib.h>
#include <dlfcn.h>

#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fd.h>
#include <linux/types.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#include <semaphore.h>
#include <netinet/in.h>

CLogger::CLogger()
{
	m_nLogDetails          = 0;
	m_szLogFileName      = NULL;
//	m_mutLog   = PTHREAD_MUTEX_INITIALIZER;
	m_pszLogBuffer       = NULL;
	m_lLogFileMaxLimit   = MAX_LOG_SIZE * NO_OF_BYTES_IN_KB; // To bytes
}

//*********************************************************************
 void CLogger::InitLogging(int nDetail, const char* szFileName,  long lLogFileMaxLimit)
{
    m_nLogDetails = nDetail;
	m_lLogFileMaxLimit = lLogFileMaxLimit * NO_OF_BYTES_IN_KB;		// Convert to bytes

    if (!szFileName)                              // Check if the log file is not specified
    {                                             // FTI
                                                  // Notify through console
        printf("Log file name is not specified\n");
        m_nLogDetails = -5;                       // Set the logging mode to "console only"
        return;                                   // Exit
    }
    
    

    if (!m_szLogFileName)
    {
        m_szLogFileName = new char[strlen(szFileName) + 1];
        strcpy(m_szLogFileName, szFileName);
        m_szLogFileName[strlen(szFileName)] = '\0';

        pthread_mutex_init(&m_mutLog, 0);         // Initialize the log mutex

/* TODO: REMOVE
        printf ( "Initialized logging...\n"
            "Log Detail\t\t:\t%d\n"
            "Log File\t\t:\t%s\n",
            nDetail,
            szFileName);*/
    }

    // do a one-time buffer allocation
    if(NULL == m_pszLogBuffer)
    {
        m_pszLogBuffer = (char*)malloc(MAX_LOG_LINESIZE);
    }
    
    
    return;
}


/****************************************************
printf like utility for logging purposes.
****************************************************/

void CLogger::log(int nPriority, const char* szTemplate, ...)
{
    pthread_mutex_lock(&m_mutLog);                // Wait and lock the output streams before writing

    FILE*   fpLog   = NULL;
    va_list list;
    timeval tvNow;
    struct tm stmNow;

    /*
    Check if the buffer is allocated
    If not, InitLogging may not be called yet
    Hence notify the user to initialize logging.
    */
    if(NULL == m_pszLogBuffer)
    {
        printf ("Logging has not been initialized.\n");
        pthread_mutex_unlock(&m_mutLog);          // Unlock the output streams before writing
        return;
    }
                                              // = 0 --> No logging
    if ( (0 == m_nLogDetails) || (nPriority > abs(m_nLogDetails)) )
    {
        pthread_mutex_unlock(&m_mutLog);          // Unlock the output streams before writing
        return;
    }

    // Add TimeStamp
    //tmNow = time(NULL);
    gettimeofday(&tvNow, NULL);
    localtime_r(&tvNow.tv_sec, &stmNow);
    sprintf(m_pszLogBuffer,"%02d/%02d/%4d %02d:%02d:%02d.%03d:TSC::",
        stmNow.tm_mday, stmNow.tm_mon + 1,  stmNow.tm_year + 1900,
        stmNow.tm_hour, stmNow.tm_min,stmNow.tm_sec,(tvNow.tv_usec/1000));

    // add the string if possible
    if(strlen(szTemplate) + strlen(m_pszLogBuffer) < MAX_LOG_LINESIZE)
    {
        int nSizeLeft;
        nSizeLeft = MAX_LOG_LINESIZE - strlen(m_pszLogBuffer) - 1;
        va_start (list, szTemplate);
        vsnprintf(m_pszLogBuffer + strlen(m_pszLogBuffer), nSizeLeft, szTemplate, list);
        va_end(list);
    }
    else
    {    	
        int nSizeLeft;
        // add a log truncated! log
        strcat(m_pszLogBuffer, "*LOG TRUNCATED*");
        nSizeLeft = MAX_LOG_LINESIZE - strlen(m_pszLogBuffer) - 1;
        va_start (list, szTemplate);
        vsnprintf(m_pszLogBuffer + strlen(m_pszLogBuffer), nSizeLeft, szTemplate, list);
        va_end(list);        
    }

    if(m_pszLogBuffer[strlen(m_pszLogBuffer)-1] != '\n')
        strcat(m_pszLogBuffer, "\n");

    if (0 > m_nLogDetails)                        // < 0 --> Screen logging
    {
        printf (m_pszLogBuffer);                  // Log to screen
        pthread_mutex_unlock(&m_mutLog);          // Unlock the output streams before writing
        return;
    }
#if 0
    fpLog = fopen(m_szLogFileName, "at");
    if (fpLog)
    {
		/*check for maximum log size and backup if needed*/
		if(ftell(fpLog) > m_lLogFileMaxLimit)
		{
			char *pszCommand = new char[512];
			fclose(fpLog);	// close current file pointer
			
			sprintf(pszCommand, "mv -f %s %s.backup", m_szLogFileName, m_szLogFileName);	// rename the file as backup overwrite if already exists
			system(pszCommand);
			fpLog = fopen(m_szLogFileName, "w"); // open new file
			
			delete []pszCommand;
		}
		
        fprintf (fpLog, m_pszLogBuffer);          // Log to file
        fclose(fpLog);
        fpLog = NULL;
    }
#endif
   // printf (m_pszLogBuffer);                      // Log to screen

    pthread_mutex_unlock(&m_mutLog);              // Unlock the output streams before writing
    return;
}


//*********************************************************************

void CLogger::EndLogging()
{
    log (5, "In EndLogging\n");

    log (1, "Logging ended.\n");
    m_nLogDetails = 0;
    delete [] m_szLogFileName;
    m_szLogFileName = NULL;

    free (m_pszLogBuffer);                        // Free the allocated buffer
    m_pszLogBuffer  = NULL;

    pthread_mutex_destroy(&m_mutLog);             // Destroy the mutex

    printf ("Exit EndLogging\n");
}
